﻿using System.Collections.Generic;
using System.Threading;

namespace System {
    /// <summary>
    /// Dictionary<TKey, TValue>
    /// <code>
    /// 定义：
    ///   private static readonly Cache<Tuple<Type, ArrayKey<Type>, string, string>, object>
    ///   MultiPocoFactories = new Cache<Tuple<Type, ArrayKey<Type>, string, string>, object>();
    /// 调用：
    ///   var key = Tuple.Create(typeof(TRet), new ArrayKey<Type>(types), connectionString, sql);
    ///    return (Func<IDataReader,object,TRet>) MultiPocoFactories.Get(key,() =>
    ///    CreateMultiPocoFactory<TRet>(types, connectionString, sql, r, defaultMapper));
    ///   清空：   MultiPocoFactories.Flush();
    /// </code>
    /// </summary>
    /// <typeparam name="TKey"></typeparam>
    /// <typeparam name="TValue"></typeparam>
    public class CacheHelper<TKey, TValue> {
        private ReaderWriterLockSlim _lock = new ReaderWriterLockSlim();
        private Dictionary<TKey,TValue> _map = new Dictionary<TKey,TValue>();
        public int Count {
            get { return _map.Count; }
        }

        public TValue Get(TKey key,Func<TValue> factory) {
            // Check cache
            _lock.EnterReadLock();
            TValue val;
            try {
                if(_map.TryGetValue(key,out val))
                    return val;
            } finally {
                _lock.ExitReadLock();
            }

            // Cache it
            _lock.EnterWriteLock();
            try {
                // Check again
                if(_map.TryGetValue(key,out val))
                    return val;
                // Create it
                val = factory();
                // Store it
                _map.Add(key,val);
                // Done
                return val;
            } finally {
                _lock.ExitWriteLock();
            }
        }

        public void Flush() {
            // Cache it
            _lock.EnterWriteLock();
            try {
                _map.Clear();
            } finally {
                _lock.ExitWriteLock();
            }
        }
    }
}